﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling;
using System.Xml;
using System.Text.RegularExpressions;

namespace Microsoft.Samples.DslTools.ConfigurationSectionDesigner
{
    public partial class ConfigurationPropertySerializer
    {

        /// <summary>
        /// Custom deserialization of ConfigurationProperty's elements. This is required because we're
        /// storing the CustomAttributes as elements.
        /// </summary>
        private static void CustomReadPropertiesFromElements( SerializationContext serializationContext, ModelElement element, XmlReader reader )
        {
            ConfigurationProperty property = (ConfigurationProperty)element;

            if( reader.Name != "customAttributes" )
            {
                ConfigurationSectionDesignerSerializationBehaviorSerializationMessages.UnexpectedXmlElement( serializationContext, reader );
                return;
            }

            XmlReader caReader = reader.ReadSubtree();
            AttributeList attributeList = new AttributeList();
            while( caReader.Read() )
            {
                switch( caReader.NodeType )
                {
                    case XmlNodeType.Element:
                        if( caReader.Name == "customAttributes" )
                            continue;

                        if( caReader.Name != "attribute" )
                        {
                            ConfigurationSectionDesignerSerializationBehaviorSerializationMessages.UnexpectedXmlElement( serializationContext, caReader );
                            continue;
                        }

                        Attribute attribute = new Attribute();
                        attributeList.AddLast( attribute );

                        while( caReader.MoveToNextAttribute() )
                        {
                            switch( caReader.Name )
                            {
                                case "name":
                                    attribute.Name = caReader.Value;
                                    break;

                                default:
                                    ConfigurationSectionDesignerSerializationBehaviorSerializationMessages.IgnoredPropertyValue( serializationContext, caReader, caReader.Name, caReader.ValueType, caReader.Value );
                                    break;
                            }
                        }

                        if( string.IsNullOrEmpty( attribute.Name.Trim() ) )
                            attribute.Name = "INVALID";

                        caReader.Read();
                        while( caReader.NodeType != XmlNodeType.Element )
                            caReader.Read();

                        if( caReader.Name != "parameters" )
                        {
                            ConfigurationSectionDesignerSerializationBehaviorSerializationMessages.UnexpectedXmlElement( serializationContext, reader );
                            continue;
                        }

                        XmlReader paReader = caReader.ReadSubtree();
                        while( paReader.Read() )
                        {
                            switch( paReader.NodeType )
                            {
                                case XmlNodeType.Element:
                                    if( paReader.Name == "parameters" ) continue;

                                    if( paReader.Name != "parameter" )
                                    {
                                        ConfigurationSectionDesignerSerializationBehaviorSerializationMessages.UnexpectedXmlElement( serializationContext, paReader );
                                        continue;
                                    }

                                    AttributeParameter parameter = new AttributeParameter();
                                    attribute.Parameters.AddLast( parameter );
                                    while( paReader.MoveToNextAttribute() )
                                    {
                                        switch( caReader.Name )
                                        {
                                            case "name":
                                                parameter.Name = paReader.Value;
                                                break;

                                            case "value":
                                                parameter.Value = paReader.Value;
                                                break;

                                            default:
                                                ConfigurationSectionDesignerSerializationBehaviorSerializationMessages.IgnoredPropertyValue( serializationContext, paReader, paReader.Name, paReader.ValueType, paReader.Value );
                                                break;
                                        }
                                    }

                                    if( string.IsNullOrEmpty( parameter.Value.Trim() ) )
                                        parameter.Value = "INVALID";
                                    break;
                            }
                        }
                        break;
                }
            }
            property.CustomAttributes = attributeList;

            reader.Skip();
            while( reader.NodeType != XmlNodeType.Element )
                reader.Skip();
        }

        /// <summary>
        /// Custom serialization of ConfigurationProperty's elements. This is required because we're
        /// storing the CustomAttributes as elements.
        /// </summary>
        private static void CustomWritePropertiesAsElements( SerializationContext serializationContext, ModelElement element, XmlWriter writer )
        {
            ConfigurationProperty property = (ConfigurationProperty)element;

            writer.WriteStartElement( "customAttributes" );
            foreach( Attribute attribute in property.CustomAttributes )
            {
                writer.WriteStartElement( "attribute" );
                writer.WriteStartAttribute( "name" );
                writer.WriteString( attribute.Name );
                writer.WriteEndAttribute();

                writer.WriteStartElement( "parameters" );
                foreach( AttributeParameter parameter in attribute.Parameters )
                {
                    writer.WriteStartElement( "parameter" );
                    if( !string.IsNullOrEmpty( parameter.Name ) )
                    {
                        writer.WriteStartAttribute( "name" );
                        writer.WriteString( parameter.Name );
                        writer.WriteEndAttribute();
                    }

                    writer.WriteStartAttribute( "value" );
                    writer.WriteString( parameter.Value );
                    writer.WriteEndAttribute();

                    writer.WriteEndElement();
                }

                writer.WriteEndElement();

                writer.WriteEndElement();
            }

            writer.WriteEndElement();
        }

        #region Use default implementations
        private void CustomConstructor()
        {
            DefaultConstructor();
        }
        
        private void CustomReadPropertiesFromAttributes( SerializationContext serializationContext, ModelElement element, XmlReader reader )
        {
            DefaultReadPropertiesFromAttributes( serializationContext, element, reader );
        }

        private void CustomWritePropertiesAsAttributes( SerializationContext serializationContext, ModelElement element, XmlWriter writer )
        {
            DefaultWritePropertiesAsAttributes( serializationContext, element, writer );
        }

        private ModelElement CustomTryCreateInstance( SerializationContext serializationContext, XmlReader reader, Partition partition )
        {
            return DefaultTryCreateInstance( serializationContext, reader, partition );
        }

        private ModelElement CustomCreateInstance( SerializationContext serializationContext, XmlReader reader, Partition partition )
        {
            return DefaultCreateInstance( serializationContext, reader, partition );
        }

        private Moniker CustomTryCreateMonikerInstance( SerializationContext serializationContext, XmlReader reader, ModelElement sourceRolePlayer, Guid relDomainClassId, Partition partition )
        {
            return DefaultTryCreateMonikerInstance( serializationContext, reader, sourceRolePlayer, relDomainClassId, partition );
        }

        private Moniker CustomCreateMonikerInstance( SerializationContext serializationContext, XmlReader reader, ModelElement sourceRolePlayer, Guid relDomainClassId, Partition partition )
        {
            return DefaultCreateMonikerInstance( serializationContext, reader, sourceRolePlayer, relDomainClassId, partition );
        }

        private string CustomCalculateQualifiedName( DomainXmlSerializerDirectory directory, ModelElement element )
        {
            return DefaultCalculateQualifiedName( directory, element );
        }

        private string CustomGetMonikerQualifier( DomainXmlSerializerDirectory directory, ModelElement element )
        {
            return DefaultGetMonikerQualifier( directory, element );
        }

        private void CustomReadElements( SerializationContext serializationContext, ModelElement element, XmlReader reader )
        {
            DefaultReadElements( serializationContext, element, reader );
        }

        private void CustomWriteElements( SerializationContext serializationContext, ModelElement element, XmlWriter writer )
        {
            // IsCustom == true, calling CustomWriteElements().
            // Provide your custom implementation with following signature:
            //   private static void CustomWriteElements(DslModeling::SerializationContext serializationContext, DslModeling::ModelElement element, global::System.Xml.XmlWriter writer);
            // You can call DefaultWriteElements() for the default implementation.
            DefaultWriteElements( serializationContext, element, writer );
        }
        #endregion
    }
}
